﻿using System;
using System.Linq;
using System.Linq.Expressions;

namespace BrightSword.Feber.Core
{
    public abstract class FunctionBuilder<TProto, TInstance, TResult> : UnaryFunctionBuilderBase<TProto, TInstance, TResult>
    {
        private Func<TInstance, TResult> _function;

        public virtual Func<TInstance, TResult> Function
        {
            get { return _function ?? (_function = BuildFunction()); }
        }

        private Func<TInstance, TResult> BuildFunction()
        {
            // join each of the expressions into a single expression using the conjunctionExpression, starting with the seed value.
            var conjoinedExpression = OperationExpressions.Aggregate(Expression.Constant(Seed),
                                                                     Conjunction);

            // create a lambda expression, wiring up the _instance parameter
            var lambdaExpression = Expression.Lambda<Func<TInstance, TResult>>(conjoinedExpression,
                                                                               InstanceParameterExpression);

            // Voila!
            return lambdaExpression.Compile();
        }
    }

    public abstract class FunctionBuilder<TProto, TLeftInstance, TRightInstance, TResult> : BinaryFunctionBuilderBase<TProto, TLeftInstance, TRightInstance, TResult>
    {
        private Func<TLeftInstance, TRightInstance, TResult> _function;

        public virtual Func<TLeftInstance, TRightInstance, TResult> Function
        {
            get { return _function ?? (_function = BuildFunction()); }
        }

        private Func<TLeftInstance, TRightInstance, TResult> BuildFunction()
        {
            // join each of the expressions into a single expression using the conjunctionExpression, starting with the seed value.
            var conjoinedExpression = OperationExpressions.Aggregate(Expression.Constant(Seed),
                                                                     Conjunction);

            // create a lambda expression, wiring up the _instance parameter
            var lambdaExpression = Expression.Lambda<Func<TLeftInstance, TRightInstance, TResult>>(conjoinedExpression,
                                                                                                   LeftInstanceParameterExpression,
                                                                                                   RightInstanceParameterExpression);

            // Voila!
            return lambdaExpression.Compile();
        }
    }
}